﻿#region License
/******************************************************************************
* Copyright 2018-2020 The AutoCore Authors. All Rights Reserved.
* 
* Licensed under the GNU Lesser General Public License, Version 3.0 (the "License"); 
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* 
* https://www.gnu.org/licenses/lgpl-3.0.html
* 
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*****************************************************************************/
#endregion


using AutoCore.MapToolbox.PCL;
using System.IO;
using UnityEditor;
using UnityEditor.Experimental.AssetImporters;
using UnityEngine;

using System.Collections.Generic;
//using UnityEngine;
//using UnityEngine.Bindings;
//using UnityEngine.Scripting;


using System.Collections;
using Unity.Collections;

using System.Threading;
using System.Timers;

public struct MeshPointType
{
    public Mesh mesh;
    public string name;
}


namespace AutoCore.MapToolbox.Editor.PCL
{


    [ScriptedImporter(1, "pcd")]
    public class PointCloudImporter : ScriptedImporter
    {

        public List<NativeArray<PointXYZI>> m_mapToolPoint = new List<NativeArray<PointXYZI>>();
        public List<GameObject> m_mapToolPointGameObject = new List<GameObject>();
        public List<string> m_mapToolPointStrName = new List<string>();

        public static Thread m_readThread;


        public List<MeshPointType> Loadpoint(string path)
        {
            string path2 = "E:\\github\\work\\RSTART\\rc\\table_scene_lms400.pcd";
            path2 = "E:\\ai\\unity\\TaggingPath\\Assets\\Scenes\\testdata\\cppcd_1.pcd";



            //string path = "E:\\ai\\pointmap\\";
            //path = "E:\\ai\\htdata\\pcd3\\";
            //path = "E:\\ai\\htdata\\pcd\\";

            if (string.IsNullOrEmpty(path))
            {
                Debug.Log("路径不存在！请重新输入" + path);
            }
            else
            {
                DirectoryInfo dir = new DirectoryInfo(path);
                if (dir.Exists == false)
                {
                    Debug.Log("路径不存在！请重新输入");
                }
                else
                {
                    FileName = "";
                    GetChildDicsName(dir);
                    Debug.Log(FileName);

                    Debug.Log("获取该路径下文件名成功！你可以继续输入新的路径");
                }
            }


            //m_readThread = new Thread(OpenRnu);
            //m_readThread.Start(path);

            return OpenRnu(path);

        }

        public List<MeshPointType> OpenRnu(string path)
        {

            List<MeshPointType> _mapToolPointMesh = new List<MeshPointType>();
            string[] b = FileName.Split(',');

            int index = 0;
            int total = b.Length;

            foreach (string c in b)
            {


                //EditorApplication.update = delegate ()
                //{
                bool isCancel = EditorUtility.DisplayCancelableProgressBar("执行中...", c, (float)index / total);
                ++index;
                if (isCancel || index >= total)
                {
                    EditorUtility.ClearProgressBar();
                    EditorApplication.update = null;
                }
                //};




                if (c.Contains(".pcd"))
                {
                    Debug.Log(path + c);

                    using (var reader = new PointCloudReader(path + c))
                    {

                        if (reader.PointXYZRGBAs.IsCreated)
                        {
                            MeshPointType _MeshPointType = new MeshPointType();
                            _MeshPointType.mesh = reader.PointXYZRGBAs.CoordinateRosToUnity().ToUnityColor().ToMesh();
                            _MeshPointType.name = path + c;
                            _mapToolPointMesh.Add(_MeshPointType);
                        }
                        else if (reader.PointXYZIs.IsCreated)
                        {
                            MeshPointType _MeshPointType = new MeshPointType();
                            var colored = reader.PointXYZIs.IntensityToColor();
                            _MeshPointType.mesh = colored.CoordinateRosToUnity().ToMesh();
                            _MeshPointType.name = path + c;
                            _mapToolPointMesh.Add(_MeshPointType);

                            colored.Dispose();
                        }
                    }
                    AssetDatabase.Refresh();

                }

            }
            return _mapToolPointMesh;
        }

        void ClipScreen()
        {
            GameObject gopoint = GameObject.CreatePrimitive(PrimitiveType.Cube);

            Camera mainCamera;
            GameObject gameObject = GameObject.Find("MainCamera");
            //GameObject gameObject = GameObject.Find("MainCameraPoint"); 
            mainCamera = gameObject.GetComponent<Camera>();

            Vector3 screen3dPos = mainCamera.WorldToScreenPoint(gopoint.transform.position);

            if (screen3dPos.x > Screen.width)

            {

                Debug.Log("out of screen");

            }
            else
            {

                Debug.Log("in screen");

            }
        }



        public void ShowPoint(List<MeshPointType> _mapToolPointMesh)
        {

            for (int i = 0; i < _mapToolPointMesh.Count; i++)
            {
                GameObject gopoint = GameObject.CreatePrimitive(PrimitiveType.Cube);
                DestroyImmediate(gopoint.GetComponent<BoxCollider>());
                gopoint.GetComponent<MeshFilter>().mesh = _mapToolPointMesh[i].mesh;
                _mapToolPointMesh[i].mesh.name = "points";
                gopoint.name = _mapToolPointMesh[i].name;
                gopoint.GetComponent<MeshRenderer>().sharedMaterial = Resources.Load<Material>("MapToolbox/PointCloud");
                //m_mapToolPointGameObject.Add(gopoint);

            }
            AssetDatabase.Refresh();
        }

        static System.Timers.Timer m_timerUpdate = new System.Timers.Timer(1000);//实例化Timer类，设置间隔时间为10000毫秒；
        static Camera mainCamera;
        static GameObject m_cube;

        [MenuItem("MapToolbox/test", false)]
        static void test()
        {
            m_cube = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            m_cube.GetComponent<Renderer>().material.color = Color.red;


        }



        [MenuItem("MapToolbox/Release", false)]
        static void ReleasePoint()
        {
            //Transform camreatra = Camera.main.transform;
            //Vector3 viewPos = Camera.main.WorldToViewportPoint(m_cube.transform.position);
            //Vector3 dir = (m_cube.transform.position - camreatra.position).normalized;
            //float dot = Vector3.Dot(camreatra.forward, dir);
            //if (dot > 0 && viewPos.x > 0 && viewPos.x < 1 && viewPos.y > 0 && viewPos.y < 1)
            //{

            //    Debug.Log("in screen=================================" + viewPos.x + "__y=" + viewPos.y);

            //}
            //else
            //{
            //    Debug.Log("out of screen=================================");

            //}


            //GameObject gameObject = GameObject.Find("MainCameraPoint");
            //Debug.Log("out of screen" + gameObject.name);
            ////GameObject gameObject = GameObject.Find("MainCameraPoint"); 
            //mainCamera = gameObject.GetComponent<Camera>();

            //Vector3 screen3dPos = mainCamera.WorldToScreenPoint(m_cube.transform.position);

            //if (screen3dPos.x > Screen.width)

            //{

            //    Debug.Log("out of screen=================================");

            //}
            //else
            //{

            //    Debug.Log("in screen=================================");

            //}


            if (IsPointInFrustum(m_cube.transform.position))

            {
                Debug.Log("in screen=================================");


            }
            else
            {
                DestroyImmediate(m_cube.GetComponent<BoxCollider>());
                Debug.Log("out of screen=================================");

            }


            m_timerUpdate.Elapsed += new System.Timers.ElapsedEventHandler(theout);//到达时间的时候执行事件；

            m_timerUpdate.AutoReset = true;//设置是执行一次（false）还是一直执行(true)；

            m_timerUpdate.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件；

            m_timerUpdate.Start();

            // m_mapToolPointMesh.Clear();
        }


        //计算摄像机的视景并返回它的六个面
        static Plane[] GetFrustumPlanes()
        {
            GameObject gameObject = GameObject.Find("MainCameraPoint");
            mainCamera = gameObject.GetComponent<Camera>();
            Camera m_Camera = Camera.main;
            return GeometryUtility.CalculateFrustumPlanes(m_Camera);
        }

        public static bool IsPointInFrustum(Vector3 point)
        {
            Plane[] planes = GetFrustumPlanes();

            for (int i = 0, iMax = planes.Length; i < iMax; ++i)
            {
                //判断一个点是否在平面的正方向上
                if (!planes[i].GetSide(point))
                    return false;
            }

            return true;
        }

        static int m_count = 0;
        public static void theout(object source, System.Timers.ElapsedEventArgs e)
        {
            Debug.Log("_____________" + m_count.ToString());

            m_count++;
            Vector3 screen3dPos = mainCamera.WorldToScreenPoint(m_cube.transform.position);

            if (screen3dPos.x > Screen.width)

            {

                Debug.Log("out of screen=================================");

            }
            else
            {

                Debug.Log("in screen=================================");

            }

        }

        public void OnGUI()
        {
            if (GUILayout.Button("in screen=================================", GUILayout.Height(50)))
            {

            }

        }

        public static string FileName = "";
        public static DirectoryInfo[] GetChildDicsName(DirectoryInfo dir)
        {
            FileInfo[] fileArray = dir.GetFiles();
            DirectoryInfo[] childDirs = dir.GetDirectories();

            foreach (FileInfo file in fileArray)
            {
                FileName += file.Name + ",";
            }
            if (childDirs.Length > 0)
            {
                foreach (DirectoryInfo dirChild in childDirs)
                {
                    GetChildDicsName(dirChild);
                }
            }
            return childDirs;
        }














        public override void OnImportAsset(AssetImportContext ctx)
        {
            using (var reader = new PointCloudReader(Path.Combine(Directory.GetCurrentDirectory(), ctx.assetPath)))
            {
                if (reader.PointXYZRGBAs.IsCreated)
                {
                    SaveMesh(ctx, reader.PointXYZRGBAs.CoordinateRosToUnity().ToUnityColor().ToMesh());
                }
                else if (reader.PointXYZIs.IsCreated)
                {
                    var colored = reader.PointXYZIs.IntensityToColor();
                    SaveMesh(ctx, colored.CoordinateRosToUnity().ToMesh());
                    colored.Dispose();
                }
            }
            AssetDatabase.Refresh();
        }
        private void SaveMesh(AssetImportContext ctx, Mesh mesh)
        {
            var go = GameObject.CreatePrimitive(PrimitiveType.Cube);
            DestroyImmediate(go.GetComponent<BoxCollider>());
            go.GetComponent<MeshFilter>().mesh = mesh;
            mesh.name = "points";
            go.GetComponent<MeshRenderer>().sharedMaterial = Resources.Load<Material>("MapToolbox/PointCloud");
            ctx.AddObjectToAsset(mesh.name, mesh);
            ctx.AddObjectToAsset(go.name, go);
            ctx.SetMainObject(go);
        }
    }
}